using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace CellarDoor.Gui.Elements
{
    public class UiListBox : UiScrollPane
    {
        #region Variables
        private bool labelsInvalid = true;
        private List<UiLabel> labels;
        private UiLabel selectedLabel;
        private int selectedIndex;

        private Color colorNormal = Microsoft.Xna.Framework.Color.White;
        private Color colorHover = Microsoft.Xna.Framework.Color.Gray;
        private Color colorSelect = Microsoft.Xna.Framework.Color.Red;
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the color used to display the items.
        /// </summary>
        public Color ColorItemNormal
        {
            get { return colorNormal; }
            set { colorNormal = value; }
        }

        /// <summary>
        /// Gets or sets the color used to display an item
        /// when mouse hovers over it.
        /// </summary>
        public Color ColorItemHover
        {
            get { return colorHover; }
            set { colorHover = value; }
        }

        /// <summary>
        /// Gets or sets the color used to display a selected item.
        /// </summary>
        public Color ColorItemSelected
        {
            get { return colorSelect; }
            set { colorSelect = value; }
        }

        /// <summary>
        /// Gets the currently selected item.
        /// </summary>
        public object SelectedItem
        {
            get { return selectedLabel != null ? selectedLabel.Tag : null; }
        }

        /// <summary>
        /// Gets and sets the selected index
        /// </summary>
        public int SelectedIndex
        {
            get { return selectedIndex; }
            set
            {
                if (selectedIndex != value)
                {
                    selectedIndex = value;
                    OnSelectedIndexChanged();
                }
            }
        }
        #endregion

        #region EventHandler
        /// <summary>
        /// Occurs when selected item has changed
        /// </summary>
        public event EventHandler SelectedItemChanged;
        #endregion

        #region Constructor
        /// <summary>
        /// Creates a new listbox.
        /// </summary>
        public UiListBox()
            : base()
        {
            Initialize();
        }

        /// <summary>
        /// Creates a new listbox.
        /// </summary>
        public UiListBox(UiElement parent)
            : base(parent)
        {
            Initialize();
        }

        private void Initialize()
        {
            ElementName = "Listbox";
            Resizeable = false;
            Dragable = false;
            labels = new List<UiLabel>();
            Container.Elements.ControlAdded += new EventHandler<UiElementEventArgs>(Elements_ControlAdded);
            Container.Elements.ControlRemoved += new EventHandler<UiElementEventArgs>(Elements_ControlRemoved);
        }
        #endregion

        #region Update
        /// <summary>
        /// Updates this component.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="buttons"></param>
        /// <param name="position"></param>
        /// <param name="wheelvalue"></param>
        public override void UpdateState(GameTime gameTime, UiMouseProxy mouse)
        {
            if (VisualState == UiVisualState.Up)
            {
                if (mouse.WheelDirection != 0)
                {
                    ScrollV.Value = ScrollV.Value - (mouse.WheelDirection > 0 ? 1 : -1) * ScrollV.StepSize;
                }
            }

            base.UpdateState(gameTime, mouse);
        }
        #endregion

        #region Methods
        private void OnSelectedIndexChanged()
        {
            if (selectedIndex >= 0 && selectedIndex < labels.Count)
            {
                selectedLabel = labels[selectedIndex];
                if (SelectedItemChanged != null)
                {
                    SelectedItemChanged(this, EventArgs.Empty);
                }
            }
            else
            {
                selectedIndex = -1;
            }
            labelsInvalid = true;
        }

        /// <summary>
        /// Adds an item to collection.
        /// </summary>
        /// <param name="item"></param>
        public void Add(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            UiLabel label = new UiLabel(this.Container);
            label.Tag = item;
        }

        /// <summary>
        /// Removes an item from list
        /// </summary>
        /// <param name="item"></param>
        public void Remove(object item)
        {
            UiLabel toRemove = null;
            foreach (UiLabel label in labels)
            {
                if (label.Tag != null && label.Tag.Equals(item))
                {
                    toRemove = label;
                }
            }
            if (toRemove != null)
            {
                toRemove.Detach();
            }
        }

        void Elements_ControlAdded(object sender, UiElementEventArgs e)
        {
            UiLabel label = e.Element as UiLabel;
            if (label != null)
            {
                label.Click += label_MouseClick;
                labels.Add(label);
                labelsInvalid = true;
            }
        }

        void Elements_ControlRemoved(object sender, UiElementEventArgs e)
        {
            UiLabel label = e.Element as UiLabel;
            if (label != null)
            {
                label.Click -= label_MouseClick;
                labels.Remove(label);
                labelsInvalid = true;
            }
        }

        /// <summary>
        /// Sets an item as selected.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void label_MouseClick(object sender, EventArgs e)
        {
            UiLabel s = sender as UiLabel;
            SelectedIndex = labels.IndexOf(s);
        }

        void label_StateChanged(object sender, EventArgs e)
        {
            UiLabel s = sender as UiLabel;
            if (!s.Equals(selectedLabel))
            {
                switch (s.VisualState)
                {
                    case UiVisualState.Up:
                        s.TextColor = colorHover.ToVector3();
                        break;
                    case UiVisualState.Down:
                        s.TextColor = colorSelect.ToVector3();
                        break;
                    default:
                        s.TextColor = colorNormal.ToVector3();
                        break;
                }
            }

        }

        private void RefreshLabels()
        {
            // update the labels text
            Vector2 position = Vector2.Zero;
            position.X += this.Padding.Left;
            position.Y += this.Padding.Top;

            for (int i = 0; i < labels.Count; i++)
            {
                UiLabel label = labels[i];
                label.Text = label.Tag.ToString();
                label.Location = position;
                position.Y += label.Height;

                switch (label.VisualState)
                {
                    case UiVisualState.Up:
                        label.TextColor = colorHover.ToVector3();
                        break;
                    case UiVisualState.Down:
                        label.TextColor = colorSelect.ToVector3();
                        break;
                    default:
                        label.TextColor = colorNormal.ToVector3();
                        break;
                }
                if (i == selectedIndex)
                {
                    label.TextColor = colorSelect.ToVector3();
                }
            }
        }
        #endregion

        public override void Draw(Vector4 color)
        {
            base.Draw(color);
            if (labelsInvalid)
            {
                
                labelsInvalid = false;
            }
            RefreshLabels();
        }
    }
}
